package com.tyx.chargingpile.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.tyx.chargingpile.Enum.ServiceExceptionEume;
import com.tyx.chargingpile.Enum.ServiceMessageEume;
import com.tyx.chargingpile.cache.SocketChannelMap;
import com.tyx.chargingpile.pojo.ChargingRecord;
import com.tyx.chargingpile.service.*;
import com.tyx.chargingpile.service.exception.ServiceExcep;
import com.tyx.chargingpile.util.DateUtils;
import com.tyx.chargingpile.util.Util;
import com.tyx.chargingpile.vo.HttpResult;
import com.tyx.chargingpile.vo.PileInfo;
import com.tyx.chargingpile.vo.SocketResponseResult;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

/**
 * 充电结束后充电记录上报处理
 */
@Service("chargingPileRecord")
public class ChargingPileRecord implements ChargingPileService {

    @Value("${chargingback.url}")
    private String url;
    @Autowired
    HttpAPIService httpAPIService;
    @Autowired
    private ChargingRecordService chargingRecordService;
    private final static Logger LOGGER = LoggerFactory.getLogger(ChargingPileRecord.class);

    @Override
    public SocketResponseResult execute(ChannelHandlerContext channelHandlerContext, byte[] context) throws Exception {
        String channelId = channelHandlerContext.channel().id().toString();
        String commandId = MessageService.getCommandControl(context);
        Map<String,String> map = MessageService.analysisMessage(context, ServiceMessageEume.RECORD.getUpLinePath());
        checkData(map);
        ChargingRecord chargingRecord = setChargingRecord(map);
        if (chargingRecord == null){
            new ServiceExcep(ServiceExceptionEume.RECORDERROR);
        }
        String pileNum = chargingRecord.getPileNum();
        pileNum = pileNum.substring(1,pileNum.length());
        PileInfo pileInfo = SocketChannelMap.getPileInfo(pileNum);
        if(pileInfo == null){
            new ServiceExcep(ServiceExceptionEume.PILEINFOCACHEISNOT);
        }
        sendChargingRecord(chargingRecord,channelId,commandId);
        Map<String ,String> dwn = new HashMap<>();
        dwn.put("gunpointNum",chargingRecord.getGunpointNum());
        dwn.put("powerType",chargingRecord.getPowerType());
        dwn.put("pileNum",chargingRecord.getPileNum());
        dwn.put("orderNum",chargingRecord.getOrderNum());
        byte[] dwnContext = MessageService.getMessage(dwn,ServiceMessageEume.RECORD.getDwnLinePath());
        ByteBuf pingMessage = Unpooled.buffer();
        pingMessage.writeBytes(dwnContext);
        channelHandlerContext.writeAndFlush(pingMessage);
        return new SocketResponseResult(channelHandlerContext,dwnContext);
    }

    @Override
    public SocketResponseResult execute(ChannelHandlerContext channelHandlerContext, Map data) throws Exception {
        return null;
    }

    /**
     * 报文业务校验
     * @param map
     * @throws ServiceExcep
     */
    private void checkData(Map<String,String> map) throws ServiceExcep {
        if(map == null){
            throw new ServiceExcep(ServiceExceptionEume.MESSAGEPARSINGERROR);
        }
    }

    private ChargingRecord setChargingRecord(Map<String,String> map){
        ChargingRecord chargingRecord = new ChargingRecord();
        chargingRecord.setGunpointNum(map.get("gunpointNum"));
        chargingRecord.setPowerType(map.get("powerType"));
        chargingRecord.setPileNum(map.get("pileNum"));
        chargingRecord.setCardNo(map.get("cardNo"));
        chargingRecord.setOrderNum(map.get("orderNum"));
        chargingRecord.setConsumeElectric(map.get("consumeElectric"));
        chargingRecord.setConsumeMoney(map.get("consumeMoney"));
        chargingRecord.setStartEndSoc(map.get("startEndSoc"));
        chargingRecord.setStartEndTime(map.get("startEndTime"));
        chargingRecord.setOrderFinishReason(map.get("orderFinishReason"));
        chargingRecord.setGunUseCount(map.get("gunUseCount"));
        chargingRecord.setVinCode(map.get("vinCode"));
        chargingRecord.setReceivedTime(DateUtils.now());
        return chargingRecord;
    }

    /**
     * 请求后台，推送充电记录
     * @param chargingRecord
     * @return
     * @throws Exception
     */
    @Async
    public void sendChargingRecord(ChargingRecord chargingRecord,String channelId,String commandId) {
        try {
            chargingRecord.setSendStatus("0"); // 未推送
            // 把充电记录插入数据库
            chargingRecordService.add(chargingRecord);
            JSONObject requestJson = new JSONObject();
            JSONObject dataJson = new JSONObject();
            // 电桩编号，去掉首位
            String deviceId = chargingRecord.getPileNum().substring(1,chargingRecord.getPileNum().length());
            // 枪口编号，hex码转成int
            byte[] gunPointNumData = Util.String2BCD(chargingRecord.getGunpointNum());
            String ChargePortIndex = Util.HexToint(gunPointNumData,gunPointNumData.length) + "";
            // 消费电量，保留小数点后2位
            String electric = Double.parseDouble(chargingRecord.getConsumeElectric()) / 100 + "";
            // 消费金额
            String amountMoney = Double.parseDouble(chargingRecord.getConsumeMoney()) / 100 + "";
            // 开始SOC
            String startSocHexStr = chargingRecord.getStartEndSoc().substring(0,2);
            byte[] startSocHex = Util.String2BCD(startSocHexStr);
            String startSoc = Util.HexToint(startSocHex,startSocHex.length) + "";
            //结束SOC
            String endSocHexStr = chargingRecord.getStartEndSoc().substring(2,chargingRecord.getStartEndSoc().length());
            byte[] endSocHex = Util.String2BCD(endSocHexStr);
            String endSoc = Util.HexToint(endSocHex,endSocHex.length) + "";
            // 开始时间
            String startTime = chargingRecord.getStartEndTime().substring(0,12);
            // 结束时间
            String endTime = chargingRecord.getStartEndTime().substring(12,chargingRecord.getStartEndTime().length());
            // 枪口使用次数
            byte[] usageCountHex = Util.String2BCD(chargingRecord.getGunUseCount());
            String usageCount = Util.HexToint(usageCountHex,usageCountHex.length) + "";
            dataJson.put("DeviceId",deviceId);
            dataJson.put("ChargePortIndex",ChargePortIndex);
            dataJson.put("OrderId",chargingRecord.getOrderNum());
            dataJson.put("CardId",chargingRecord.getCardNo());
            dataJson.put("Electric",electric);
            dataJson.put("AmountMoney",amountMoney);
            dataJson.put("BeginSOC",startSoc);
            dataJson.put("EndSOC",endSoc);
            dataJson.put("BeginTime",startTime);
            dataJson.put("EndTime",endTime);
            dataJson.put("OrderResult",chargingRecord.getOrderFinishReason());
            dataJson.put("UsageCount",usageCount);
            dataJson.put("VINCode",chargingRecord.getVinCode());
            requestJson.put("MainCMD",68);
            requestJson.put("SubCMD",4);
            requestJson.put("Data",dataJson);
//            LOGGER.info("充电记录推送至后台：" + requestJson.toJSONString());
            LOGGER.info("客户端"+channelId+",指令控制编号："+commandId+",桩编号:" + deviceId + ",枪口编号--" + ChargePortIndex + ",订单编号--" + chargingRecord.getOrderNum() + ",充电记录推送至后台：" + requestJson.toJSONString());
            HttpResult result = httpAPIService.doPost2Json(url,requestJson.toJSONString());
            boolean isOk;
            if(result.getCode() != 200){
//                LOGGER.info("充电记录推送至后台：false");
                LOGGER.info("客户端"+channelId+",指令控制编号："+commandId+",桩编号:" + deviceId + ",枪口编号--" + ChargePortIndex + ",订单编号--" + chargingRecord.getOrderNum() + ",充电记录推送至后台：false");
                isOk = false;
            }
            LOGGER.info("充电记录推送至后台：true");
            LOGGER.info("客户端"+channelId+",指令控制编号："+commandId+",桩编号:" + deviceId + ",枪口编号--" + ChargePortIndex + ",订单编号--" + chargingRecord.getOrderNum() + ",充电记录推送至后台：true");
            isOk = true;
            if (isOk){
                chargingRecord.setSendStatus("1");
            }else {
                chargingRecord.setSendStatus("2");
            }
            // 把充电记录插入数据库
            chargingRecordService.add(chargingRecord);
        } catch (Exception e){
            e.printStackTrace();
//            LOGGER.info("充电记录推送至后台: 报错" + e.getMessage());
            LOGGER.info("客户端"+channelId+",指令控制编号："+commandId+ ",订单编号--" + chargingRecord.getOrderNum() + ",充电记录推送至后台：报错" + e.getMessage());
        }
    }
}
